package com.xiaoh.dormitoryrepairreportbackend.aspect;

import com.xiaoh.dormitoryrepairreportbackend.annotation.RequireRole;
import com.xiaoh.dormitoryrepairreportbackend.common.ErrorCode;
import com.xiaoh.dormitoryrepairreportbackend.exception.BusinessException;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.GeneralUser;
import com.xiaoh.dormitoryrepairreportbackend.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 权限控制切面
 */
@Aspect
@Component
@Slf4j
public class AuthAspect {

    @Around("@annotation(com.xiaoh.dormitoryrepairreportbackend.annotation.RequireRole)")
    public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequireRole requireRole = method.getAnnotation(RequireRole.class);
        
        if (requireRole == null) {
            return joinPoint.proceed();
        }
        
        // 获取当前用户
        GeneralUser currentUser;
        try {
            currentUser = UserHolder.getCurrentUser();
        } catch (Exception e) {
            log.error("获取当前用户失败", e);
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        
        // 检查角色权限
        int[] requiredRoles = requireRole.value();
        boolean hasRole = Arrays.stream(requiredRoles)
                .anyMatch(role -> currentUser.getUserType() != null && role == currentUser.getUserType());
        
        if (hasRole) {
            // 有角色权限，直接通过
            return joinPoint.proceed();
        }
        
        // 检查是否允许操作自己的资源
        if (requireRole.allowSelf()) {
            Long targetUserId = extractTargetUserId(joinPoint, requireRole.targetUserIdParam());
            if (targetUserId != null && targetUserId.equals(currentUser.getId())) {
                // 操作自己的资源，允许通过
                return joinPoint.proceed();
            }
        }
        
        // 无权限
        log.warn("用户 {} 尝试访问需要权限 {} 的方法 {}", 
                currentUser.getId(), Arrays.toString(requiredRoles), method.getName());
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    }
    
    /**
     * 从方法参数中提取目标用户ID
     */
    private Long extractTargetUserId(ProceedingJoinPoint joinPoint, String paramName) {
        Object[] args = joinPoint.getArgs();
        
        for (Object arg : args) {
            if (arg == null) {
                continue;
            }
            
            try {
                // 尝试通过反射获取指定字段
                Field field = arg.getClass().getDeclaredField(paramName);
                field.setAccessible(true);
                Object value = field.get(arg);
                
                if (value instanceof Long) {
                    return (Long) value;
                } else if (value instanceof Integer) {
                    return ((Integer) value).longValue();
                } else if (value instanceof String) {
                    return Long.parseLong((String) value);
                }
            } catch (Exception e) {
                // 忽略异常，继续尝试下一个参数
                log.debug("无法从参数 {} 中提取字段 {}: {}", arg.getClass().getSimpleName(), paramName, e.getMessage());
            }
        }
        
        return null;
    }
}
